package com.loong.coupon.handler;

import com.loong.common.domain.Pager;
import com.loong.common.enumerate.CouponSource;
import com.loong.common.enumerate.CouponStatus;
import com.loong.common.enumerate.CouponType;
import com.loong.common.exception.GlobalException;
import com.loong.common.executor.BatchExecutor;
import com.loong.common.utils.TransformUtils;
import com.loong.coupon.business.CouponBusiness;
import com.loong.coupon.common.backend.param.CouponAndApplyRuleParam;
import com.loong.coupon.common.backend.param.CouponApplyRuleParam;
import com.loong.coupon.common.backend.param.CouponParam;
import com.loong.coupon.common.backend.param.CouponQueryParam;
import com.loong.coupon.common.backend.result.CouponApplyRuleResult;
import com.loong.coupon.common.backend.result.CouponResult;
import com.loong.coupon.common.backend.result.CouponTypeOrSourceResult;
import com.loong.coupon.model.Coupon;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description: 处理优惠券相关请求的handler
 * @Author: LiuQun
 * @Date: 2021/1/7 16:47
 */
@Service
public class CouponHandler {

    @Resource
    private CouponBusiness couponBusiness;

    @Resource
    private CouponApplyRuleHandler ruleHandler;

    @Resource
    private BatchExecutor batchExecutor;

    @Resource
    private UserCouponHandler userCouponHandler;

    /**
     * 后台新增优惠券和优惠券适用规则
     *
     * @param param 优惠券参数
     */
    @Transactional
    public void saveCouponAndApplyRule(CouponAndApplyRuleParam param) {
        Date date = new Date();
        //新增优惠券到数据库
        CouponParam couponParam = param.getCouponParam();
        couponParam.setCreateTime(date);
        couponParam.setStatus(CouponStatus.UNAUDITED.getCode());//新增的优惠券都还没有审核
        Coupon coupon = TransformUtils.transform(couponParam, Coupon.class);
        couponBusiness.save(coupon);
        //新增优惠券使用规则到数据库
        List<CouponApplyRuleParam> ruleParamList = param.getRuleParamList();
        for (CouponApplyRuleParam ruleParam : ruleParamList) {
            //设置优惠券id
            ruleParam.setId(coupon.getId());
            ruleParam.setCreateTime(date);
        }
        ruleHandler.saveCouponApplyRule(ruleParamList);
    }

    /**
     * 后端查询优惠券详情
     * @param couponId 优惠券id
     * @return 优惠券结果
     */
    public CouponResult findCouponDetail(Long couponId){
        //根据优惠券id查询优惠券
        Coupon coupon = couponBusiness.findById(couponId);
        CouponResult couponResult = TransformUtils.transform(coupon, CouponResult.class);
        //根据优惠券id查询优惠券适用规则
        List<CouponApplyRuleResult> ruleResultList = ruleHandler.findCouponApplyRuleByCouponId(couponId);
        couponResult.setRuleResultList(ruleResultList);
        return couponResult;
    }

    /**
     * 后台更新优惠券和优惠券适用规则
     *
     * @param param 优惠券参数
     */
    @Transactional
    public void updateCouponAndApplyRule(CouponAndApplyRuleParam param) {
        //更新优惠券
        CouponParam couponParam = param.getCouponParam();
        couponParam.setLastUpdateTime(new Date());
        couponBusiness.updateByPrimaryKeySelective(TransformUtils.transform(param, Coupon.class));
        //更新优惠券适用规则
        List<CouponApplyRuleParam> ruleParamList = param.getRuleParamList();
        ruleHandler.updateCouponApplyRule(ruleParamList);
    }

    /**
     * 后台更新优惠券的状态
     * @param couponId 优惠券id
     * @param status 优惠券状态
     */
    public void updateCouponStatus(Long couponId,Integer status){
        CouponParam param = CouponParam.builder()
                .id(couponId)
                .status(status)
                .lastUpdateTime(new Date())
                .build();
        couponBusiness.updateByPrimaryKeySelective(TransformUtils.transform(param,Coupon.class));
    }

    /**
     * 后台分页查询优惠券：这里暂时只查询出了优惠券信息，优惠券适用规则没有查询，若需要的话可能需要联表查询
     * @param param 优惠券查询参
     * @return 分页结果
     */
    public Pager<CouponResult> pageQueryCoupon(CouponQueryParam param){
        Pager<Coupon> pager = couponBusiness.pageQuery(param, () -> couponBusiness.findCouponByParam(param));
        return TransformUtils.transformPage(pager,CouponResult.class);
    }

    /**
     * 后台批量删除优惠券
     * @param idList 优惠券id集合
     */
    @Transactional
    public void batchDeleteCoupon(List<Long> idList){
        batchExecutor.batchExecute(idList,id -> id.toString(),(item) -> {
            //根据优惠券id查询该优惠券是否已通过审核，若已通过则不能删除
            List<Coupon> couponList = couponBusiness.findApprovedCouponByCouponId(item);
            //根据优惠券id查询用户券关联表中是否有对应的记录，若有则不能删除。
            boolean flag = userCouponHandler.nonexistentUserCoupon(item);
            if (CollectionUtils.isEmpty(couponList) && flag){
                //删除该优惠券下的适用规则
                ruleHandler.deleteCouponApplyRule(item);
                //删除该优惠券券
                couponBusiness.deleteById(item);
            }else {
                throw new GlobalException("coupon is used");
            }
        });
    }

    /**
     * 获取优惠券类型
     * @return 优惠券类型结果集合
     */
    public List<CouponTypeOrSourceResult> getCouponType(){
        List<CouponTypeOrSourceResult> resultList = new ArrayList<>();
        //获取优惠券类型枚举类中的所有值
        CouponType[] couponTypeList = CouponType.values();
        for (CouponType couponType : couponTypeList) {
            CouponTypeOrSourceResult result = CouponTypeOrSourceResult.builder()
                    .code(couponType.getCode())
                    .desc(couponType.getDesc())
                    .build();
            resultList.add(result);
        }
        return resultList;
    }

    /**
     * 获取优惠券来源
     * @return 优惠券来源结果集合
     */
    public List<CouponTypeOrSourceResult> getCouponSource(){
        List<CouponTypeOrSourceResult> resultList = new ArrayList<>();
        //获取优惠券来源枚举类中的所有值
        CouponSource[] couponSources = CouponSource.values();
        for (CouponSource couponSource : couponSources) {
            CouponTypeOrSourceResult result = CouponTypeOrSourceResult.builder()
                    .code(couponSource.getCode())
                    .desc(couponSource.getDesc())
                    .build();
            resultList.add(result);
        }
        return resultList;
    }

}
